package com.isyscore.os.metadata.service.impl;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.isyscore.os.core.exception.DataFactoryException;
import com.isyscore.os.metadata.common.CommonService;
import com.isyscore.os.metadata.dao.ErRelationMapper;
import com.isyscore.os.metadata.database.AbstractDatabase;
import com.isyscore.os.metadata.manager.DatabaseManager;
import com.isyscore.os.metadata.model.dto.DataSourceDTO;
import com.isyscore.os.metadata.model.dto.ERTableInfoDTO;
import com.isyscore.os.metadata.model.dto.ERTableRelationDTO;
import com.isyscore.os.metadata.model.dto.req.CreateERRelationReq;
import com.isyscore.os.metadata.model.entity.ErRelation;
import com.isyscore.os.metadata.utils.ColumnUtil;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import static com.isyscore.os.core.exception.ErrorCode.DATA_NOT_FOUND;
import static java.util.Collections.emptyList;

/**
 * <p>
 * 存储ER关系 服务实现类
 * </p>
 *
 * @author
 * @since 2021-08-11
 */
@Service
public class ErRelationService extends CommonService<ErRelationMapper, ErRelation> {

    public String parseSQLFromERrelations(String databaseName, DataSourceDTO dataSource, CreateERRelationReq req) {
        AbstractDatabase db = DatabaseManager.findDb(dataSource);
        StringBuilder sql = new StringBuilder();
        String mainTableAlias = StrUtil.toCamelCase(req.getCenterTable());
        Map<String, Set<ERTableRelationDTO>> linkTablesMap = Maps.newHashMap();
        //首先按照从表表名对join的字段进行聚合，方便后续操作
        for (ERTableRelationDTO erTableRelationDto : req.getTableRelations()) {
            Set<ERTableRelationDTO> joinCols = linkTablesMap.get(erTableRelationDto.getLinkTable());
            if (joinCols == null) {
                joinCols = Sets.newHashSet();
            }
            joinCols.add(erTableRelationDto);
            linkTablesMap.put(erTableRelationDto.getLinkTable(), joinCols);
        }
        Set<String> duplicateColumns = ColumnUtil.getDuplicateColumnsForErTable(req.getTableInfos());
        sql.append("SELECT ");
        for (ERTableInfoDTO tableInfo : req.getTableInfos()) {
            String tableAlias = StrUtil.toCamelCase(tableInfo.getTableName());
            for (String column : tableInfo.getColumns()) {
                sql.append(tableAlias);
                sql.append(".");
                sql.append(db.escapeColName(column));
                //如果选择了多张表的同名字段，则必须为每个字段添加一个别名，加上表名前缀
                if (duplicateColumns.contains(column)) {
                    String columnAliasName = ColumnUtil.getColName(duplicateColumns, column, tableInfo.getTableName());
                    sql.append(" AS ");
                    sql.append(db.escapeColAliasName(columnAliasName));
                }
                sql.append(",");
            }
        }
        sql.deleteCharAt(sql.lastIndexOf(","));
        sql.append(" FROM ");
        sql.append(db.escapeTbName(req.getCenterTable(), databaseName));
        sql.append(" ");
        sql.append(mainTableAlias);
        Set<String> linkTableNames = linkTablesMap.keySet();
        for (String table : linkTableNames) {
            String tableAlias = StrUtil.toCamelCase(table);
            sql.append(" INNER JOIN ");
            sql.append(db.escapeTbName(table, databaseName));
            sql.append(" ");
            sql.append(tableAlias);
            sql.append(" ON ");
            for (ERTableRelationDTO linkInfo : linkTablesMap.get(table)) {
                sql.append(mainTableAlias + "." + db.escapeColName(linkInfo.getCenterColumn()));
                sql.append("=");
                sql.append(tableAlias + "." + db.escapeColName(linkInfo.getLinkColumn()));
                sql.append(" AND ");
            }
            //删除结尾多余的AND
            sql.delete(sql.length() - 5, sql.length());
        }
        return sql.toString();
    }

    public String getErRelationById(Long id) {
        ErRelation erRelation = this.getById(id);
        if (erRelation != null) {
            return erRelation.getErLayoutData();
        } else {
            throw new DataFactoryException(DATA_NOT_FOUND, "ER关系数据");
        }
    }

    public void importData(List<ErRelation> erRelations) {
        if (erRelations.isEmpty()) {
            return;
        }
        Set<Long> ids = erRelations.stream().map(ErRelation::getId).collect(Collectors.toSet());
        LambdaQueryWrapper<ErRelation> qw = new LambdaQueryWrapper<ErRelation>();
        qw.in(ErRelation::getId, ids);
        this.remove(qw);
        this.saveBatch(erRelations);
    }

    public List<ErRelation> getDataByIds(Set<Long> ids) {
        if (ids.isEmpty()) {
            return emptyList();
        }
        LambdaQueryWrapper<ErRelation> qw = new LambdaQueryWrapper<ErRelation>();
        qw.in(ErRelation::getId, ids);
        return this.list(qw);
    }

}
